library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use ieee.numeric_std.all;


entity memory_stage is
generic (numBit : integer := 32;
			ramSize: integer := 6);
port( clk 		: in  std_logic;
		rst 		: in  std_logic;
		enb 		: in  std_logic;
		cond		: in  std_logic; 								-- for the mux_0
		sel		: in  std_logic; 								-- for the mux_1
		mem_wr	: in  std_logic;								-- '0' read from mem, '1' write in mem
		mem_cnt	: in  std_logic_vector (1 downto 0);	-- memory control signal (ld/st 32,16,8 bits)
		B_in		: in  std_logic_vector (numBit-1 downto 0);	-- data from the register B
		ALU_in	: in  std_logic_vector (numBit-1 downto 0);	-- data from the output of the ALU
		NewPC		: in  std_logic_vector (numBit-1 downto 0);	-- data from the NPC register
		mux_out	: out std_logic_vector (numBit-1 downto 0);	-- output from the second mux
		result	: out std_logic_vector (numBit-1 downto 0);	-- output from the datamem
		NPC_final: out std_logic_vector (numBit-1 downto 0)	-- real NPC sent to the PC
);
end memory_stage;

architecture Structural of memory_stage is

component RAM is
generic (DATA : integer := 32;
			ADDR : integer := 8);
port( clock		: in  std_logic;
		reset		: in  std_logic;
		write_en	: in  std_logic;
		addr_in 	: in  std_logic_vector (ADDR-1 downto 0);
      data_in	: in  std_logic_vector (DATA-1 downto 0);
      data_out	: out std_logic_vector (DATA-1 downto 0)  
);
end component;

component muxer
generic (N : integer := 32);
port(	data_0 : in  std_logic_vector (N-1 downto 0);
		data_1 : in  std_logic_vector (N-1 downto 0);
		sel 	 : in  std_logic;
		output : out std_logic_vector (N-1 downto 0)
);
end component;

component reg is
generic (N : integer :=32);
port( clock		: in  std_logic;
		reset		: in  std_logic;
		enable	: in  std_logic;
		data_in 	: in  std_logic_vector (N-1 downto 0);
		data_out : out std_logic_vector (N-1 downto 0)
);
end component;

component splitter is
generic (N : integer := 32);
port(	data_in  : in  std_logic_vector (N-1 downto 0);
		control  : in  std_logic_vector (1 downto 0);
		data_out : out std_logic_vector (N-1 downto 0)
);
end component;

signal mem_in  : std_logic_vector (numBit-1 downto 0);
signal mem_out : std_logic_vector (numBit-1 downto 0);
signal NPC		: std_logic_vector (numBit-1 downto 0);
begin

MUX_0		 : muxer generic map (numBit) port --this is for the NPC sent to the IF
map ( NewPC,ALU_in,cond,NPC );

MUX_1		 : muxer generic map (numBit) port --this is for saving the NPC in the register file sent to the WB
map ( ALU_in,NewPC,sel,mux_out );

SPLIT_in  : splitter generic map (numBit) port
map ( data_in  => B_in,
		control  => mem_cnt,
		data_out => mem_in
);

SPLIT_out : splitter generic map (numBit) port
map ( data_in  => mem_out,
		control  => mem_cnt,
		data_out => result
);

MEM		 : RAM generic map (numBit,ramSize) port
map ( clock		=> clk,
		reset		=> rst,
		write_en	=> mem_wr,
		addr_in  => ALU_in (ramSize-1 downto 0),
      data_in	=> mem_in,
      data_out	=> mem_out
);

PCreg		 : reg generic map(numBit) port
map ( clk,rst,enb,NPC,NPC_final );

end Structural;